/*
* Copyright (c) 2016 ShopJsp. All Rights Reserved.
 * ============================================================================
 * 版权所有 2011 - 今 北京华宇盈通科技有限公司，并保留所有权利。
 * ----------------------------------------------------------------------------
 * 提示：在未取得SHOPJSP商业授权之前，您不能将本软件应用于商业用途，否则SHOPJSP将保留追究的权力。
 * ----------------------------------------------------------------------------
 * 官方网站：http://www.shopjsp.com
 * ============================================================================
*/
package com.hyyt.shopjsp.solr.utils;


import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;

import com.hyyt.shopjsp.util.common.LoggerUtils;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.apache.solr.client.solrj.response.FacetField;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.client.solrj.response.UpdateResponse;
import org.apache.solr.common.params.SolrParams;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.hyyt.shopjsp.product.vo.SearchProductVo;

/**
 * Solr服务器工具类
 *
 * @author ankang 2016-08-10 11:39:38
 */
@Service
public final class SolrServerUtils {

    private HttpSolrClient httpSolrClient;

    protected volatile boolean inited;

    protected ReentrantLock lock;

    private String baseUrl;
    private int soTimeout;
    private int conTimeout;
    private int maxTotalConnectins;
    private int maxConnectionsPerHost;
    private boolean followRedirects;
    private boolean allowCompression;
    private int maxRetries;

    /**
     * 服务初始化
     *
     * @throws InterruptedException 初始化异常
     */
    public void init() throws InterruptedException {
        if (!this.inited) {
            ReentrantLock lock = this.lock;
            lock.lockInterruptibly();
            if (this.inited) {
                return;
            }
            try {
                httpSolrClient = new HttpSolrClient(this.getBaseUrl());                          //solr 服务地址
                httpSolrClient.setSoTimeout(this.getSoTimeout());                                // socket 读取时间
                httpSolrClient.setConnectionTimeout(this.getConTimeout());                       //建立连接的最长时间
                httpSolrClient.setDefaultMaxConnectionsPerHost(this.getMaxConnectionsPerHost()); //最大允许单个用户最大访问数
                httpSolrClient.setMaxTotalConnections(this.getMaxTotalConnectins());             //允许重定向
                httpSolrClient.setFollowRedirects(this.isFollowRedirects());                     // defaults to false
                httpSolrClient.setAllowCompression(this.isAllowCompression());                   //减少服务器交换的数据量
            } finally {
                this.inited = true;
                lock.unlock();
            }
        }
    }

    /**
     * 关闭搜索引擎服务器
     */
    public void shutdown() {
        this.lock.lock();
        try {
            httpSolrClient.close();
        } catch (IOException e) {
            LoggerUtils.error(this.getClass(),"SolrServerUtils",e);
        } finally {
            this.lock.unlock();
        }
    }

    /**
     * 查询
     *
     * @param params 查询参数
     * @return 商品VO集合
     * @throws SolrServerException 异常
     */
    public List<SearchProductVo> query(SolrParams params) throws SolrServerException, IOException {
        QueryResponse rsp = httpSolrClient.query(params);
        List<SearchProductVo> productList = null;
        if (null != rsp) {
            // 高亮显示部分
            Map<String, Map<String, List<String>>> hightlight = rsp.getHighlighting();
            String json = JSON.toJSONString(rsp.getResults());
            productList = JSON.parseArray(json, SearchProductVo.class);
            if (hightlight != null) {
                for (SearchProductVo product : productList) {
                    Map<String, List<String>> hlMap = hightlight.get(String.valueOf(product.getProductId()));
                    if (hlMap != null && !hlMap.isEmpty()) {
                        List<String> strings = hlMap.get("productFullName");
                        if (null != strings) {
                            StringBuilder sb = new StringBuilder();
                            for (String s : strings) {
                                sb.append(s);
                            }
                            product.setProductFullName(sb.toString());
                        }
                    }
                }
            }
        }
        return productList;
    }

    /**
     * 统计记录
     *
     * @param params 查询参数
     * @return 记录数量统计
     * @throws Exception 异常
     */
    public int count(SolrQuery params) {
        int count = 0;
        QueryResponse rsp = null;
        try {
            rsp = httpSolrClient.query(params);
            count = (int) rsp.getResults().getNumFound();
        } catch (SolrServerException e) {
            LoggerUtils.error(this.getClass(),"SolrServerUtils",e);
        } catch (IOException e) {
            LoggerUtils.error(this.getClass(),"SolrServerUtils",e);
        }
        return count;
    }

    /**
     * 自动补全
     *
     * @param params 查询参数
     * @return 结果集
     * @throws SolrServerException 异常
     */
    public Map<String, List<Map<String, Object>>> autoComplete(SolrParams params) throws SolrServerException, IOException {
        QueryResponse rsp = httpSolrClient.query(params);
        Map<String, List<Map<String, Object>>> result = null;
        if (null != rsp) {
            List<FacetField> facetFields = rsp.getFacetFields();
            result = new HashMap<String, List<Map<String, Object>>>();
            for (FacetField facetField : facetFields) {
                List<FacetField.Count> ffCountList = facetField.getValues();
                List<Map<String, Object>> ffcMapList = new ArrayList<Map<String, Object>>();
                for (FacetField.Count ffCount : ffCountList) {
                    Map<String, Object> ffcMap = new HashMap<String, Object>();
                    ffcMap.put("name", ffCount.getName());
                    ffcMap.put("count", ffCount.getCount());
                    ffcMapList.add(ffcMap);
                }
                result.put(facetField.getName(), ffcMapList);
            }
        } else {
            return null;
        }
        return result;
    }

    /**
     * 删除索引
     *
     * @param productId      商品sku
     * @param commitWithinMs 多少秒后提交操作，-1表示立即提交操作
     * @return 状态码
     * @throws Exception 异常
     */
    public int deleteById(int productId, int commitWithinMs) throws Exception {
        UpdateResponse response = httpSolrClient.deleteById(String.valueOf(productId), commitWithinMs);
        httpSolrClient.commit();
        return response.getStatus();
    }

    /**
     * 批量删除索引
     *
     * @param skuList        商品sku集合
     * @param commitWithinMs 多少秒后提交操作，-1表示立即提交操作
     * @return 状态码
     * @throws Exception 异常
     */
    public int deleteById(List<String> skuList, int commitWithinMs) throws Exception {
        UpdateResponse response = httpSolrClient.deleteById(skuList, commitWithinMs);
        return response.getStatus();
    }

    /**
     * 删除索引
     *
     * @param query 查询条件
     * @return 状态码
     * @throws Exception 异常
     */
    public int deleteByQuery(String query, int commitWithinMs) throws Exception {
        UpdateResponse response = httpSolrClient.deleteByQuery(query, commitWithinMs);
        httpSolrClient.commit();
        return response.getStatus();
    }

    /**
     * 文档新增
     * 策略：如果存在就先删除，再新增，如果不存在直接新增。是否存在的依据是定义的uniqueKey字段即sku.
     *
     * @param productInfo 商品信息
     * @return 状态码
     */
    public int addItem(SearchProductVo productInfo, int commitWithinMs) throws Exception {
        UpdateResponse response = httpSolrClient.addBean(productInfo, commitWithinMs);
        return response.getStatus();
    }

    /**
     * 批量文档新增
     * 策略：如果存在就先删除，再新增，如果不存在直接新增。是否存在的依据是定义的uniqueKey字段即sku.
     *
     * @param searchItemVOList 商品VO集合
     * @return 状态码
     */
    public int addItem(List<SearchProductVo> searchItemVOList, int commitWithinMs) throws Exception {
        UpdateResponse response = httpSolrClient.addBeans(searchItemVOList, commitWithinMs);
        return response.getStatus();
    }


    public int getSoTimeout() {
        return soTimeout;
    }

    public void setSoTimeout(int soTimeout) {
        this.soTimeout = soTimeout;
    }

    public int getConTimeout() {
        return conTimeout;
    }

    public void setConTimeout(int conTimeout) {
        this.conTimeout = conTimeout;
    }

    public int getMaxTotalConnectins() {
        return maxTotalConnectins;
    }

    public void setMaxTotalConnectins(int maxTotalConnectins) {
        this.maxTotalConnectins = maxTotalConnectins;
    }

    public int getMaxConnectionsPerHost() {
        return maxConnectionsPerHost;
    }

    public void setMaxConnectionsPerHost(int maxConnectionsPerHost) {
        this.maxConnectionsPerHost = maxConnectionsPerHost;
    }

    public boolean isFollowRedirects() {
        return followRedirects;
    }

    public void setFollowRedirects(boolean followRedirects) {
        this.followRedirects = followRedirects;
    }

    public boolean isAllowCompression() {
        return allowCompression;
    }

    public void setAllowCompression(boolean allowCompression) {
        this.allowCompression = allowCompression;
    }

    public int getMaxRetries() {
        return maxRetries;
    }

    public void setMaxRetries(int maxRetries) {
        this.maxRetries = maxRetries;
    }

    public String getBaseUrl() {
        return baseUrl;
    }

    public void setBaseUrl(String baseUrl) {
        this.baseUrl = baseUrl;
    }

    private SolrServerUtils() {
        this.lock = new ReentrantLock(false);
    }
}
